home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 4 / QRZ Ham Radio Callsign Database - Volume 4.iso / files / tcpip / amiga / asrc29p.lha / chatnode.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-29  |  29.1 KB  |  1,103 lines

  1. /* convers server - based on conversd written by DK5SG
  2.  * ported to WNOS by DB3FL - 9109xx/9110xx
  3.  *
  4.  * Ported to NOS and many mods and bug fixes by SM6RPZ
  5.  * 1992-01-10 - 1992-04-09 No history. Some fixes taken from PE1NMB and PA0GRI.
  6.  * 1992-04-09 -    Added prototypes to all functions.
  7.  * 1992-04-12 - Added L:s in timestring()  It used 32767 as seconds
  8.  *        per day before :-)  Also added L:s on other places.
  9.  * 1992-07-09 - Changes inspired by WNOS ver 4a8
  10.  *          - Changed all arrays in struct convection and struct permlink
  11.  *        to pointers.
  12.  *          - Added getarg() and changed some functions to use it.
  13.  *          -    Raised stacksize on cperm from 1024 to 2048.
  14.  *          - Myhostname changed to Hostname and hostname not needed anymore
  15.  *        in converse.cfg
  16.  *          - Some small fixes here and there.
  17.  * 1992-07-11 - SOBUF changed from 256 to 2048 in usock.h to make us able
  18.  *        to use 2048 bytes in our buffers.
  19.  * 1992-07-18 - There's no reason to run in the permlink loop if we don't have
  20.  *        any links. A check for this is made (idea from WG7J ver 1.03).
  21.  *        Imported into AmigaNos by oz1dti. Thanks Lars!
  22.  */
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include <time.h>
  26. #include <ctype.h>
  27. #ifdef    UNIX
  28. #include <sys/types.h>
  29. #include <sys/stat.h>
  30. #endif
  31. #ifndef AMIGA
  32. #include <io.h>
  33. #endif
  34. #include "global.h"
  35. #include "config.h"
  36. #ifdef CHATNODE
  37. #ifdef MAILBOX
  38. #include "mailbox.h"
  39. #include "netuser.h"
  40. #endif
  41. #include "timer.h"
  42. #include "cmdparse.h"
  43. #include "socket.h"
  44. #include "session.h"
  45. #include "files.h"
  46. #include "commands.h"
  47.  
  48. static struct convection *convections;    /* Not Used in mailbox.c */
  49.  
  50. #define LINK        1   /* Start LINK -- SM6RPZ */
  51.  
  52. #define MAXCHANNEL    32767
  53. #define LINELEN     256
  54. #define    CBUFLEN        2048
  55. #define MAX_WAITTIME    (60L*60L*3L)
  56.  
  57. struct convection {
  58.   int  type;                    /* Connection type */
  59. #define CT_UNKNOWN      0
  60. #define CT_USER         1
  61. #define CT_HOST         2
  62. #define CT_CLOSED       3
  63.   char  *name;              /* Name of user or host */
  64.   char  *host;            /* Name of host where user is logged on */
  65.   struct convection *via;       /* Pointer to neighbor host */
  66.   int  channel;                 /* Channel number */
  67.   int32 time;                   /* Connect time */
  68.   int  locked;                  /* Set if mesg already sent */
  69.   int  fd;                /* Socket descriptor */
  70.   int  fmask;                   /* Socket mask */
  71.   char *ibuf;            /* Input buffer */
  72.   int  received;                /* Number of bytes received */
  73.   int  xmitted;                 /* Number of bytes transmitted */
  74.   struct convection *next;      /* Linked list pointer */
  75. };
  76. #define NULLCONNECTION  ((struct convection *) 0)
  77.  
  78. #define CM_UNKNOWN   (1 << CT_UNKNOWN)
  79. #define CM_USER      (1 << CT_USER)
  80. #define CM_HOST      (1 << CT_HOST)
  81. #define CM_CLOSED    (1 << CT_CLOSED)
  82.  
  83. /* in convers.c */
  84. static struct convection *convections;  /* Not Used in mailbox.c */
  85. static char *timestring __ARGS((long gmt));    /* Not Used in mailbox.c */
  86.  
  87.  
  88. struct permlink {
  89.   char *name;                  /* Name of host */
  90.   char *link_info;                /* Name of socket to connect to */
  91.   char *command;         /* Optional connect command */
  92.   struct convection *convection;/* Pointer to associated connection */
  93.   int32 statetime;              /* Time of last (dis)connect */
  94.   int tries;            /* Number of connect tries */
  95.   int32 waittime;               /* Time between connect tries */
  96.   int32 retrytime;              /* Time of next connect try */
  97.   int fd;            /* socket descriptor */
  98.   struct permlink *next;        /* Linked list pointer */
  99. };
  100. #define NULLPERMLINK  ((struct permlink *) 0)
  101.  
  102. static struct permlink *permlinks;
  103. static int Sconv = -1;
  104. static int Inlink = 0;    /* links acceptance -oz1dti*/
  105.  
  106. static void free_connection __ARGS((register struct convection *cp));
  107. static void free_closed_connections __ARGS((void));
  108. static void update_permlinks __ARGS((char *name,struct convection *cp));
  109. static struct convection *alloc_connection __ARGS((int fd));
  110. static char *getarg __ARGS((char *line, int all));
  111. #ifdef LINK
  112. static char links = 0;
  113. static void connect_permlinks __ARGS((int a,void *b,void *c));
  114. #endif
  115. static void clear_locks __ARGS((void));
  116. static void send_user_change_msg __ARGS((char *name,char *host,int oldchannel,int newchannel));
  117. static char *formatline __ARGS((char *prefix,char *text));
  118. static void send_msg_to_user __ARGS((char *fromname,char *toname,char *text));
  119. static void send_msg_to_channel __ARGS((char *fromname,int channel,char *text));
  120. static void send_invite_msg __ARGS((char *fromname,char *toname,int  channel));
  121. static void bye_command __ARGS((struct convection *cp));
  122. static void channel_command __ARGS((struct convection *cp));
  123. static void help_command __ARGS((struct convection *cp));
  124. static void invite_command __ARGS((struct convection *cp));
  125. static void links_command __ARGS((struct convection *cp));
  126. static void msg_command __ARGS((struct convection *cp));
  127. static void name_command __ARGS((struct convection *cp));
  128. static void who_command __ARGS((struct convection *cp));
  129. static void h_cmsg_command __ARGS((struct convection *cp));
  130. static void h_host_command __ARGS((struct convection *cp));
  131. static void h_invi_command __ARGS((struct convection *cp));
  132. static void h_loop_command __ARGS((struct convection *cp));
  133. static void h_umsg_command __ARGS((struct convection *cp));
  134. static void h_user_command __ARGS((struct convection *cp));
  135. static void conv_incom __ARGS((int s,void *t,void *p));
  136.  
  137. /* Stop convers server */
  138. int
  139. conv0(argc,argv,p)
  140. int argc;
  141. char *argv[];
  142. void *p;
  143. {
  144.     close_s(Sconv);
  145.     Sconv = -1;
  146.     return 0;
  147. }
  148.  
  149. /* Start up convers server */
  150. int
  151. conv1(argc,argv,p)
  152. int argc;
  153. char *argv[];
  154. void *p;
  155. {
  156.     struct sockaddr_in lsocket;
  157.     int s;
  158. #ifdef LINK
  159.     struct proc *child;
  160. #endif
  161.  
  162.     if(Sconv != -1)
  163.     return 0;
  164.  
  165.     psignal(Curproc,0);     /* Don't keep the parser waiting */
  166.     chname(Curproc,"Chatnode listener");
  167.  
  168.     lsocket.sin_family = AF_INET;
  169.     lsocket.sin_addr.s_addr = INADDR_ANY;
  170.     lsocket.sin_port = (argc < 2) ? IPPORT_CHATNODE : atoi(argv[1]);
  171.  
  172.     Sconv = socket(AF_INET,SOCK_STREAM,0);
  173.     bind(Sconv,(char *)&lsocket,sizeof(lsocket));
  174.     if(listen(Sconv,1) == -1) {
  175.     close_s(Sconv);
  176.     Sconv = -1;
  177.     return 0;
  178.     }
  179. #ifdef LINK
  180.     child = newproc("cperm",2048,connect_permlinks,0,0,NULL);
  181. #endif
  182.     for(;;) {
  183.     if((s = accept(Sconv,NULLCHAR,(int *)NULL)) == -1)
  184.         break;            /* Service is shutting down */
  185.     if(availmem() < Memthresh + 16384L)
  186.         shutdown(s,1);        /* Not enough memory */
  187.     else
  188.         newproc("chatnode",2048,conv_incom,s,0,NULL);/* Spawn a server */
  189.     }
  190. #ifdef LINK
  191.     if(links)
  192.     killproc(child);
  193. #endif
  194.     close_s(Sconv);
  195.     Sconv = -1;
  196.     return 0;
  197. }
  198.  
  199. static char *
  200. getarg(line,all)
  201. char *line;
  202. int all;
  203. {
  204.     char *arg;
  205.     int c;
  206.     static char *p;
  207.  
  208.     if(line)
  209.     p = line;
  210.     while(isspace(uchar(*p)))
  211.     p++;
  212.     if(all)
  213.     return p;
  214.     arg = p;
  215.     while(*p && !isspace(uchar(*p))) {
  216.     c = tolower(uchar(*p));
  217.     *p++ = c;
  218.     }
  219.     if(*p)
  220.     *p++ = '\0';
  221.     return arg;
  222. }
  223.  
  224. static void
  225. free_connection(cp)
  226. register struct convection *cp;
  227. {
  228.     register struct permlink *p;
  229.  
  230.     for(p = permlinks; p; p = p->next)
  231.     if(p->convection == cp)
  232.         p->convection = NULLCONNECTION;
  233.     if(cp->fmask)
  234.     close_s(cp->fd);
  235.     free(cp->name);
  236.     free(cp->host);
  237.     free(cp->ibuf);
  238.     free((char *) cp);
  239. }
  240.  
  241. static void
  242. free_closed_connections()
  243. {
  244.     register struct convection *cp,*p;
  245.     time_t currtime;
  246.  
  247.     for(p = NULLCONNECTION,cp = convections; cp; )
  248.         if(cp->type == CT_CLOSED ||    
  249.        cp->type == CT_UNKNOWN && cp->time + 300L < time(&currtime)) {
  250.         if(p) {
  251.         p->next = cp->next;
  252.         free_connection(cp);
  253.         cp = p->next;
  254.         } else {
  255.         convections = cp->next;
  256.         free_connection(cp);
  257.         cp = convections;
  258.         }
  259.         } else {
  260.         p = cp;
  261.         cp = cp->next;
  262.     }
  263. }
  264.  
  265. static void
  266. update_permlinks(name,cp)
  267. char *name;
  268. struct convection *cp;
  269. {
  270.     register struct permlink *p;
  271.     time_t currtime;
  272.  
  273.     for(p = permlinks; p; p = p->next)
  274.         if(!strcmp(p->name,name)) {
  275.             p->convection = cp;
  276.             p->statetime = time(&currtime);
  277.             p->tries = 0;
  278.             p->waittime = 60L;
  279.             p->retrytime = currtime + p->waittime;
  280.         }
  281. }
  282.  
  283. static struct convection *
  284. alloc_connection(fd)
  285. int  fd;
  286. {
  287.     register struct convection *cp;
  288.     time_t currtime;
  289.  
  290.     cp = (struct convection *)callocw(1,sizeof(struct convection));
  291.     cp->name = NULLCHAR;
  292.     cp->host = NULLCHAR;
  293.     cp->time = time(&currtime);
  294.     cp->fd = cp->fmask = fd;
  295.     cp->ibuf = mallocw(CBUFLEN+1);
  296.     cp->next = convections;
  297.     convections = cp;
  298.     return cp;
  299. }
  300.  
  301. #ifdef LINK
  302. static void
  303. connect_permlinks(a,b,c)
  304. int a;
  305. void *b;
  306. void *c;
  307. {
  308.     int s,len = SOCKSIZE;
  309.     register struct permlink *p;
  310.     struct sockaddr_in cport;
  311.     FILE *fp;
  312.     char *host_name, *link_info, *command, line[LINELEN];
  313.     time_t currtime;
  314.  
  315.     if((fp = fopen(Chatnode,"r")) != NULLFILE) {
  316.     Inlink = 1;    /* linkrequests will be accepted -oz1dti */
  317.     while(fgets(line,LINELEN,fp)) {
  318.         rip(line);
  319.         if(*line == '#' || *line == '\0')
  320.             continue;
  321.         host_name = getarg(line,0);
  322.         link_info = getarg(0,0);
  323.         command = getarg(0,0);
  324.         if(host_name != NULLCHAR && link_info != NULLCHAR) {
  325.             p = (struct permlink *)callocw(1,sizeof(struct permlink ));
  326.             p->name = strdup(host_name);
  327.             p->link_info = strdup(link_info);
  328.             if(command != NULLCHAR)
  329.             p->command = strdup(command);
  330.             p->next = permlinks;
  331.             permlinks = p;
  332.             update_permlinks(host_name,NULLCONNECTION);
  333.         }
  334.     }
  335.     fclose(fp);
  336.     }
  337.  
  338.     /* If the're no links, there's no reason to stay alive - WG7J */
  339.     if(permlinks == NULLPERMLINK)
  340.         return;
  341.  
  342.     links = 1;            /* This process has to be killed */
  343.  
  344.     for(;;) {
  345.     pause(1000L);
  346.     for(p = permlinks; p; p = p->next) {
  347.         if(p->convection || p->retrytime > time(&currtime))
  348.         continue;
  349.         p->tries++;
  350.         p->waittime <<= 1;
  351.         if(p->waittime > MAX_WAITTIME)
  352.         p->waittime = MAX_WAITTIME;
  353.         p->retrytime = p->waittime + currtime;
  354.         switch(tolower(*p->link_info)) {
  355.         case 't':        /* telnet connection */
  356.             cport.sin_family = AF_INET;
  357.             cport.sin_port = IPPORT_CHATNODE;
  358.             if((cport.sin_addr.s_addr = resolve(p->name)) == 0)
  359.             continue;
  360.         if((s = socket(AF_INET,SOCK_STREAM,0)) == -1)
  361.             continue;
  362.         mainlog(s,"PERMLINK trying %s",p->name);
  363.         if(connect(s,(char *)&cport,len) == -1) {
  364.             mainlog(s,"PERMLINK reset received from %s",p->name);
  365.             close_s(s);
  366.             continue;
  367.         }
  368.         mainlog(s,"PERMLINK connected to %s",p->name);
  369.         break;
  370. #ifdef notdef            /* Not implemented yet! */
  371.         case 'a':        /* ax25 connection */
  372.         case 'n':        /* netrom connection */
  373. #endif
  374.         default:
  375.             continue;
  376.         }
  377.         p->fd = s;
  378.         newproc("permlink",1024,conv_incom,s,0,NULL);
  379.     }
  380.     }
  381. }
  382. #endif
  383.  
  384. static void
  385. clear_locks()
  386. {
  387.     register struct convection *p;
  388.  
  389.     for(p = convections; p; p = p->next)
  390.     p->locked = 0;
  391. }
  392.  
  393. static void
  394. send_user_change_msg(name,host,oldchannel,newchannel)
  395. char  *name,*host;
  396. int  oldchannel,newchannel;
  397. {
  398.     register struct convection *p;
  399.  
  400.     for(p = convections; p; p = p->next) {
  401.     if(p->type == CT_USER && !p->via && !p->locked) {
  402.         if(p->channel == oldchannel) {
  403.         if(newchannel >= 0)
  404.             p->xmitted += usprintf(p->fd,
  405.             "*** %s switched to channel %d.\n",name,newchannel);
  406.         else
  407.             p->xmitted += usprintf(p->fd,"*** %s signed off.\n",name);
  408.         p->locked = 1;
  409.         }
  410.         if(p->channel == newchannel) {
  411.         p->xmitted += usprintf(p->fd,"\007\007*** %s signed on.\n",name);
  412.         p->locked = 1;
  413.         }
  414.     }
  415.     if(p->type == CT_HOST && !p->locked) {
  416.         p->xmitted += usprintf(p->fd,"/\377\200USER %s %s 0 %d %d\n",
  417.         name,host,oldchannel,newchannel);
  418.         p->locked = 1;
  419.     }
  420.     }
  421.     return;
  422. }
  423.  
  424. static char *
  425. formatline(prefix,text)
  426. char  *prefix,*text;
  427. {
  428. #define PREFIXLEN 10
  429. #define CONVLINELEN   79
  430.     register char *f, *t, *x;
  431.     register int l, lw;
  432.     static char buf[CBUFLEN];
  433.  
  434.     for(f = prefix,t = buf; *f; *t++ = *f++)
  435.     ;
  436.     l = (int)(t - buf);
  437.     f = text;
  438.  
  439.     for(;;) {
  440.     while(isspace(uchar(*f)))
  441.         f++;
  442.     if(!*f) {
  443.         *t++ = '\n';
  444.         *t = '\0';
  445.         return buf;
  446.     }
  447.     for(x = f; *x && !isspace(uchar(*x)); x++)
  448.         ;
  449.     lw = (int)(x - f);
  450.     if(l > PREFIXLEN && l + 1 + lw > CONVLINELEN) {
  451.         *t++ = '\n';
  452.         l = 0;
  453.     }
  454.     do {
  455.         *t++ = ' ';
  456.         l++;
  457.     } while(l < PREFIXLEN);
  458.     while(lw--) {
  459.         *t++ = *f++;
  460.         l++;
  461.     }
  462.     }
  463. }
  464.  
  465. static void
  466. send_msg_to_user(fromname,toname,text)
  467. char  *fromname,*toname,*text;
  468. {
  469.     register struct convection *p;
  470.     char *buffer = mallocw(CBUFLEN+1);
  471.  
  472.     for(p = convections; p; p = p->next) {
  473.     if(p->type == CT_USER && !strcmp(p->name,toname))
  474.         if(p->via) {
  475.         if(!p->via->locked) {
  476.             p->via->xmitted += usprintf(p->via->fd,
  477.             "/\377\200UMSG %s %s %s",fromname,toname,text);
  478.             p->via->locked = 1;
  479.         }
  480.         } else {
  481.         if(!p->locked) {
  482.             if(strcmp(fromname,"chatnode")) {
  483.             sprintf(buffer,"<*%s*>:",fromname);
  484.             p->xmitted += usprintf(p->fd,"%s",
  485.                 formatline(buffer,text));
  486.             } else
  487.             p->xmitted += usprintf(p->fd,"%s\n",text);
  488.             p->locked = 1;
  489.         }
  490.         }
  491.     }
  492.     free(buffer);
  493.     return;
  494. }
  495.  
  496. static void
  497. send_msg_to_channel(fromname,channel,text)
  498. char  *fromname;
  499. int  channel;
  500. char  *text;
  501. {
  502.     char *buffer = mallocw(CBUFLEN+1);
  503.     register struct convection *p;
  504.  
  505.     for(p = convections; p; p = p->next) {
  506.     if(p->type == CT_USER && p->channel == channel)
  507.         if(p->via) {
  508.         if(!p->via->locked) {
  509.             p->via->xmitted += usprintf(p->via->fd,
  510.             "/\377\200CMSG %s %d %s\n",fromname,channel,text);
  511.             p->via->locked = 1;
  512.         }
  513.         } else {
  514.         if(!p->locked) {
  515.             sprintf(buffer,"<%s>:",fromname);
  516. /*            p->xmitted += usprintf(p->fd,"%s",formatline(&buffer[0],text));*/
  517.             p->xmitted += usprintf(p->fd,"%s",formatline(buffer,text));
  518.             p->locked = 1;
  519.         }
  520.         }
  521.     }
  522.     free(buffer);
  523.     return;
  524. }
  525.  
  526. char *
  527. timestring(gmt)                /* used in mailbox.c */
  528. long gmt;
  529. {
  530.     static char buffer[10];
  531.     struct tm *tm;
  532.     time_t currtime;
  533.     extern char *Months[];        /* in smtpserv.c */
  534.  
  535.     tm = localtime(&gmt);
  536.     if(gmt + 24L * 60L * 60L > time(&currtime))
  537.         sprintf(buffer," %2d:%02d",tm->tm_hour,tm->tm_min);
  538.     else
  539.         sprintf(buffer,"%-3.3s %2d",Months[tm->tm_mon],tm->tm_mday);
  540.     return buffer;
  541. }
  542.  
  543. static void
  544. send_invite_msg(fromname,toname,channel)
  545. char  *fromname,*toname;
  546. int  channel;
  547. {
  548.     char invitetext[] = "\n\007\007*** Message from %s at%s ...\nPlease join chatnode channel %d.\n\007\007\n";
  549.     char mbinvitetext[] = "\n\007\007*** Message from %s at%s ...\nPlease type 'C' to join chatnode, then goto channel %d.\n\007\007\n";
  550.     char responsetext[] = "*** Invitation sent to %s @ %s";
  551.     char cnvd[] = "chatnode";
  552.     char *buffer = mallocw(CBUFLEN+1);
  553.     register struct convection *p;
  554.     time_t currtime;
  555. #ifdef MAILBOX
  556.     int i;
  557.     struct mbx *m;
  558. #endif
  559.  
  560.     currtime = time(&currtime);
  561.     for(p = convections; p; p = p->next) {
  562. #ifdef MAILBOX
  563.         for(i = 0; i < NUMMBX; i++){
  564.             if((m = Mbox[i]) != NULLMBX){
  565.             if(m->state == MBX_CMD && !strcmp(m->name,toname)) {
  566.                 p->xmitted += usprintf(m->user,mbinvitetext,fromname,timestring(currtime),channel);
  567.                 usflush(m->user);
  568.                 clear_locks();
  569.                 sprintf(buffer,responsetext,toname,"LocBBS@");
  570.                 strcat(buffer,Hostname);
  571.                 send_msg_to_user(cnvd,fromname,buffer);
  572.                 free(buffer);
  573.                 return;
  574.             }
  575.             }
  576.         }
  577. #endif
  578.         if(p->type == CT_USER && !strcmp(p->name,toname)) {
  579.                     if(p->channel == channel) {
  580.                         clear_locks();
  581.                         sprintf(buffer,"*** User %s is already on this channel.",toname);
  582.                         send_msg_to_user(cnvd,fromname,buffer);
  583.             free(buffer);
  584.                         return;
  585.                     }
  586.                     if(!p->via && !p->locked) {
  587.                         p->xmitted += usprintf(p->fd,invitetext,fromname,timestring(currtime),channel);
  588.                         clear_locks();
  589.                         sprintf(buffer,responsetext,toname,Hostname);
  590.                         send_msg_to_user(cnvd,fromname,buffer);
  591.             free(buffer);
  592.                         return;
  593.                     }
  594.                     if(p->via && !p->via->locked) {
  595.                         p->via->xmitted += usprintf(p->via->fd,
  596.                             "/\377\200INVI %s %s %d\n",fromname,toname,channel);
  597.             free(buffer);
  598.                         return;
  599.                     }
  600.                 }
  601.         if(p->type == CT_HOST && !p->locked) {
  602.                     p->xmitted += usprintf(p->fd,"/\377\200INVI %s %s %d\n",fromname,toname,channel);
  603.             free(buffer);
  604.             return;
  605.         }
  606.     }
  607.     free(buffer);
  608.     return;
  609. }
  610.  
  611. static void
  612. bye_command(cp)
  613. struct convection *cp;
  614. {
  615.     register struct convection *p;
  616.  
  617.         if(cp->type != CT_CLOSED)
  618.                 mainlog(cp->fd,"close CHATNODE");
  619.         switch(cp->type) {
  620.     case CT_UNKNOWN:
  621.         cp->type = CT_CLOSED;
  622.         break;
  623.     case CT_USER:
  624.         cp->type = CT_CLOSED;
  625.         clear_locks();
  626.         send_user_change_msg(cp->name,cp->host,cp->channel,-1);
  627.         break;
  628.     case CT_HOST:
  629.         cp->type = CT_CLOSED;
  630.         update_permlinks(cp->name,NULLCONNECTION);
  631.                 for(p = convections; p; p = p->next)
  632.                     if(p->via == cp) {
  633.                         p->type = CT_CLOSED;
  634.                         clear_locks();
  635.                         send_user_change_msg(p->name,p->host,p->channel,-1);
  636.                     }
  637.         break;
  638.     case CT_CLOSED:
  639.         break;
  640.     }
  641. }
  642.  
  643. static void
  644. channel_command(cp)
  645. struct convection *cp;
  646. {
  647.     int newchannel;
  648.     char *s = getarg(0,0);
  649.  
  650.     if(!*s) {
  651.     cp->xmitted += usprintf(cp->fd,"*** You are on channel %d.\n",cp->channel);
  652.     return;
  653.     }
  654.     newchannel = atoi(s);
  655.     if(newchannel < 0 || newchannel > MAXCHANNEL) {
  656.     cp->xmitted += usprintf(cp->fd,
  657.         "*** Channel numbers must be in the range 0..%d.\n",MAXCHANNEL);
  658.         return;
  659.     }
  660.     if(newchannel == cp->channel) {
  661.         cp->xmitted += usprintf(cp->fd,"*** Already on channel %d.\n",cp->channel);
  662.     return;
  663.     }
  664.     send_user_change_msg(cp->name,cp->host,cp->channel,newchannel);
  665.     cp->channel = newchannel;
  666.     cp->xmitted += usprintf(cp->fd,"*** Now on channel %d.\n",cp->channel);
  667.     return;
  668. }
  669.  
  670. static void
  671. help_command(cp)
  672. struct convection *cp;
  673. {
  674.     cp->xmitted += usprintf(cp->fd,"Commands may be abbreviated. Commands are:\n");
  675.     cp->xmitted += usprintf(cp->fd,"/? or /help           Print help information\n");
  676.     cp->xmitted += usprintf(cp->fd,"/bye                  Terminate the chatnode session\n");
  677.     cp->xmitted += usprintf(cp->fd,"/channel <n>          Switch to channel n\n");
  678.     cp->xmitted += usprintf(cp->fd,"/exit                 Terminate the chatnode session\n");
  679.     cp->xmitted += usprintf(cp->fd,"/invite <user>        Invite user to join your channel\n");
  680.     cp->xmitted += usprintf(cp->fd,"/links [long]         List all connections to other hosts\n");
  681.     cp->xmitted += usprintf(cp->fd,"/msg <user> text...   Send a private message to user\n");
  682.     cp->xmitted += usprintf(cp->fd,"/quit                 Terminate the chatnode session\n");
  683.     cp->xmitted += usprintf(cp->fd,"/who [quick] [long]   List all users and their channel numbers\n");
  684.     cp->xmitted += usprintf(cp->fd,"/write <user> text... Send a private message to user\n***\n");
  685.     return;
  686. }
  687.  
  688. static void
  689. invite_command(cp)
  690. struct convection *cp;
  691. {
  692.     char *toname = getarg(0,0);
  693.  
  694.     if(*toname)
  695.     send_invite_msg(cp->name,toname,cp->channel);
  696.     return;
  697. }
  698.  
  699. static void
  700. links_command(cp)
  701. struct convection *cp;
  702. {
  703.     register struct convection *pc;
  704.     register struct permlink *pp;
  705.     char tmp[20];
  706.     char full = *(getarg(0,0));
  707.  
  708.     cp->xmitted += usprintf(cp->fd,"Host            State         Since%s\n",
  709.                 full ? "  NextTry Tries Receivd Xmitted" : "");
  710.     for(pc = convections; pc; pc = pc->next)
  711.         if(pc->type == CT_HOST) {
  712.             cp->xmitted += usprintf(cp->fd,
  713.                             full ?
  714.                             "%-15.15s %-12s %s                %7d %7d\n" :
  715.                             "%-15.15s %-12s %s\n",
  716.                             pc->name,
  717.                             "Connected",
  718.                             timestring(pc->time),
  719.                             pc->received,
  720.                             pc->xmitted);
  721.         }
  722.     for(pp = permlinks; pp; pp = pp->next)
  723.         if(!pp->convection || pp->convection->type != CT_HOST) {
  724.             strcpy(tmp,timestring(pp->retrytime));
  725.             cp->xmitted += usprintf(cp->fd,
  726.                 full ?
  727.                 "%-15.15s %-12s %s   %s %5d\n" :
  728.                 "%-15.15s %-12s %s\n",
  729.                 pp->name,
  730.                 pp->convection ? "Connecting" : "Disconnected",
  731.                 timestring(pp->statetime),
  732.                 tmp,
  733.                 pp->tries);
  734.     }
  735.     cp->xmitted += usprintf(cp->fd,"***\n");
  736.     return;
  737. }
  738.  
  739. static void
  740. msg_command(cp)
  741. struct convection *cp;
  742. {
  743.     register struct convection *p;
  744.     char *toname = getarg(0,0);
  745.     char *text = getarg(0,1);
  746.  
  747.     if(!*text)
  748.         return;
  749.     for(p = convections; p; p = p->next)
  750.         if(p->type == CT_USER && !strcmp(p->name,toname))
  751.             break;
  752.     if(!p)
  753.         cp->xmitted += usprintf(cp->fd,"*** No such user: %s.\n",toname);
  754.     else
  755.         send_msg_to_user(cp->name,toname,text);
  756.     return;
  757. }
  758.  
  759. static void
  760. name_command(cp)
  761. struct convection *cp;
  762. {
  763.     int newchannel;
  764.     char *s = getarg(0,0);
  765.  
  766.     if(!*s)
  767.     return;
  768.     cp->name = strdup(s);
  769.     strlwr(cp->name);
  770.     cp->host = strdup(Hostname);
  771.     cp->type = CT_USER;
  772.     cp->xmitted += usprintf(cp->fd,
  773.     "*** Welcome to the %s Conference System.  Type /? for help ***\n",Hostname);
  774.     newchannel = atoi(getarg(0,0));
  775.     if(newchannel < 0 || newchannel > MAXCHANNEL)
  776.         cp->xmitted += usprintf(cp->fd,
  777.         "*** Channel numbers must be in the range 0..%d.\n",MAXCHANNEL);
  778.     else
  779.     cp->channel = newchannel;
  780.     mainlog(cp->fd,"CHATNODE login: %s",cp->name);
  781.     send_user_change_msg(cp->name,cp->host,-1,cp->channel);
  782.     return;
  783. }
  784.  
  785. static void
  786. who_command(cp)
  787. struct convection *cp;
  788. {
  789.     int channel,full = 0,quick = 0;
  790.     register struct convection *p;
  791. #ifdef MAILBOX
  792.     int i;
  793.     struct mbx *m;
  794. #endif
  795.     char *buffer = mallocw(CBUFLEN+1);
  796.  
  797.     switch(*(getarg(0,0))) {
  798.     case 'l':
  799.         full = 1;
  800.         break;
  801.     case 'q':
  802.         quick = 1;
  803.         break;
  804.     }
  805.  
  806.     if(quick) {
  807.         cp->xmitted += usprintf(cp->fd,"Channel Users\n");
  808.         clear_locks();
  809.         do {
  810.             channel = -1;
  811.             for(p = convections; p; p = p->next) {
  812.                 if(p->type == CT_USER && !p->locked &&
  813.                                     (channel < 0 || channel == p->channel)) {
  814.                     if(channel < 0) {
  815.                         channel = p->channel;
  816.                         sprintf(buffer,"%7d",channel);
  817.                     }
  818.                     strcat(buffer," ");
  819.                     strcat(buffer,p->name);
  820.                     p->locked = 1;
  821.                 }
  822.             }
  823.             if(channel >= 0) {
  824.                 cp->xmitted += usprintf(cp->fd,"%s\n",buffer);
  825.             }
  826.         } while(channel >= 0);
  827.     } else {
  828.         cp->xmitted += usprintf(cp->fd,
  829.             "User     Host            Via             Channel   Since%s\n",
  830.             full ? "  Receivd Xmitted" : "");
  831.         for(p = convections; p; p = p->next) {
  832.             if(p->type == CT_USER) {
  833.                 cp->xmitted += usprintf(cp->fd,
  834.                     full ?
  835.                 "%-8.8s %-15.15s %-15.15s %7d  %s  %7d %7d\n" :
  836.                 "%-8.8s %-15.15s %-15.15s %7d  %s\n",
  837.                     p->name,
  838.                     p->host,
  839.                     p->via ? p->via->name : "",
  840.                     p->channel,
  841.                     timestring(p->time),
  842.                     p->received,
  843.                     p->xmitted);
  844.             }
  845.         }
  846.     }
  847. #ifdef MAILBOX
  848.     for(i = 0; i < NUMMBX; i++)
  849.             if((m = Mbox[i]) != NULLMBX)
  850.         if(m->state == MBX_CMD)
  851.                     if(quick)
  852.             cp->xmitted += usprintf(cp->fd," LocBBS %s\n",m->name);
  853.                     else
  854.             cp->xmitted += usprintf(cp->fd,"%-8s LocBBS@%s\n",m->name,Hostname);
  855. #endif
  856.     cp->xmitted += usprintf(cp->fd,"***\n");
  857.     free(buffer);
  858.     return;
  859. }
  860.  
  861. static void
  862. h_cmsg_command(cp)
  863. struct convection *cp;
  864. {
  865.     char *name = getarg(0,0);
  866.     int channel = atoi(getarg(0,0));
  867.     char *text = getarg(0,1);
  868.  
  869.     if(*text)
  870.     send_msg_to_channel(name, channel, text);
  871. }
  872.  
  873. static void
  874. h_host_command(cp)
  875. struct convection *cp;
  876. {
  877.     register struct convection *p;
  878.     register struct permlink *pp;
  879.     char *name = getarg(0,0);
  880.  
  881.     if(!*name)
  882.     return;
  883.     for(p = convections; p; p = p->next)
  884.     if(!strcmp(p->name,name))
  885.         bye_command(p);
  886.     for(pp = permlinks; pp; pp = pp->next)
  887.     if(!strcmp(pp->name,name) && pp->convection && pp->convection != cp)
  888.         bye_command((strcmp(Hostname,name) < 0) ? pp->convection : cp);
  889.     if(cp->type != CT_UNKNOWN)
  890.     return;
  891.     if(Inlink != 1)    /* link acceptance -oz1dti*/
  892.     return;
  893.     cp->type = CT_HOST;
  894.     cp->name = strdup(name);
  895.     update_permlinks(name,cp);
  896.     cp->xmitted += usprintf(cp->fd,"/\377\200HOST %s\n",Hostname);
  897.     for(p = convections; p; p = p->next)
  898.     if(p->type == CT_USER)
  899.         cp->xmitted += usprintf(cp->fd,
  900.         "/\377\200USER %s %s 0 -1 %d\n",p->name,p->host,p->channel);
  901.     mainlog(cp->fd,"PERMLINK login: %s",cp->name);
  902.     return;
  903. }
  904.  
  905. static void
  906. h_invi_command(cp)
  907. struct convection *cp;
  908. {
  909.     char *fromname = getarg(0,0);
  910.     char *toname = getarg(0,0);
  911.     int channel = atoi(getarg(0,0));
  912.  
  913.     send_invite_msg(fromname, toname, channel);
  914. }
  915.  
  916. static void
  917. h_loop_command(cp)
  918. struct convection *cp;
  919. {
  920.     char *host = getarg(0,0);
  921.  
  922.     mainlog(cp->fd, "chatnode rx: LOOP %s",host);
  923.     bye_command(cp);
  924. }
  925.  
  926. static void
  927. h_umsg_command(cp)
  928. struct convection *cp;
  929. {
  930.     char *fromname = getarg(0,0);
  931.     char *toname = getarg(0,0);
  932.     char *text = getarg(0,1);
  933.  
  934.     if(*text)
  935.     send_msg_to_user(fromname, toname, text);
  936. }
  937.  
  938. static void
  939. h_user_command(cp)
  940. struct convection *cp;
  941. {
  942.     int oldchannel, newchannel;
  943.     register struct convection *p;
  944.     time_t currtime;
  945.     char *name = getarg(0,0);
  946.     char *host = getarg(0,0);
  947.     getarg(0,0);    /* ignore this argument, protocol has changed */
  948.     oldchannel = atoi(getarg(0,0));
  949.     newchannel = atoi(getarg(0,0));
  950.  
  951.     for(p = convections; p; p = p->next)
  952.     if(p->type == CT_USER) {
  953.             /* new 920705 dl9sau */
  954.             /* If Neighbour2 registers a user on HostX, while someone has already
  955.              * been registered for HostX via Neighbour1, then we definitely have
  956.              * a loop !  We send a loop detect message and then close the link:
  957.              * /..LOOP <myhostname> <myneighbour> <host>
  958.              *
  959.              * The LOOP PREVENTION CODE detects ONLY a loop if it starts at this
  960.              * host. That's, why I suggest this code to be implemented in every
  961.              * conversd implementation.
  962.              */
  963.             if (oldchannel < 0 && p->via != cp && !strcmp(p->host, host)) {
  964.                 usprintf(cp->fd,"/\377\200LOOP %s %s %s\n",
  965.                     Hostname, host,p->via ? p->via->name : Hostname);
  966.                 mainlog(cp->fd, "chatnode sent: LOOP %s",host);
  967.                 bye_command(cp);
  968.                 return;
  969.          }
  970.      if(p->channel == oldchannel &&
  971.         p->via == cp &&
  972.             !strcmp(p->name,name) &&
  973.         !strcmp(p->host,host))
  974.             break;
  975.     }
  976.     if(!p) {
  977.     p = (struct convection *)callocw(1,sizeof(struct convection));
  978.     p->type = CT_USER;
  979.     p->name = strdup(name);
  980.     p->host = strdup(host);
  981.     p->via = cp;
  982.     p->channel = oldchannel;
  983.     p->time = time(&currtime);
  984.     p->next = convections;
  985.     convections = p;
  986.     }
  987.     if((p->channel = newchannel) < 0)
  988.     p->type = CT_CLOSED;
  989.     send_user_change_msg(name,host,oldchannel,newchannel);
  990.     if(oldchannel == -1)
  991.     mainlog(p->fd,"CHATNODE login: %s host: %s",p->name,p->host);
  992.     if(newchannel == -1)
  993.     mainlog(p->fd,"CHATNODE logout: %s host: %s",p->name,p->host);
  994.     return;
  995. }
  996.  
  997. /* Incoming convers session */
  998. static void
  999. conv_incom(s,t,p)
  1000. int s;
  1001. void *t;
  1002. void *p;
  1003. {
  1004.     int arglen,size;
  1005.     char permlink = 0;
  1006.     register struct convection *cp;
  1007.     register struct permlink *pl;
  1008.     char *arg,*ccp,*cccp;
  1009. #ifdef MAILBOX
  1010.     int len;
  1011.     char fsocket[MAXSOCKSIZE];
  1012. #endif
  1013.     static struct cmdtable {
  1014.     char  *name;
  1015.     void (*fnc) __ARGS((struct convection *cp)); /* decl added -oz1dti */
  1016.     int  states;
  1017.     } cmdtable[] = {
  1018.     "?",        help_command,        CM_USER,
  1019.     "bye",        bye_command,        CM_USER,
  1020.     "channel",    channel_command,    CM_USER,
  1021.     "exit",        bye_command,        CM_USER,
  1022.     "help",        help_command,        CM_USER,
  1023.     "invite",    invite_command,        CM_USER,
  1024.     "links",    links_command,        CM_USER,
  1025.     "msg",        msg_command,        CM_USER,
  1026.     "name",        name_command,        CM_UNKNOWN,
  1027.     "quit",        bye_command,        CM_USER,
  1028.     "who",        who_command,        CM_USER,
  1029.     "write",    msg_command,        CM_USER,
  1030.  
  1031.     "\377\200cmsg",    h_cmsg_command,        CM_HOST,
  1032.     "\377\200host",    h_host_command,        CM_UNKNOWN,
  1033.     "\377\200loop", h_loop_command,        CM_HOST,
  1034.     "\377\200invi",    h_invi_command,        CM_HOST,
  1035.     "\377\200umsg",    h_umsg_command,        CM_HOST,
  1036.     "\377\200user",    h_user_command,        CM_HOST,
  1037.     0,        0,            0,
  1038.     };
  1039.     struct cmdtable *cmdp;
  1040.  
  1041.     sockowner(s,Curproc);    /* We own it now */
  1042. /*    sockmode(s,SOCK_BINARY); Not in current version -oz1dti */
  1043.     cp = alloc_connection(s);
  1044.     mainlog(cp->fd,"open CHATNODE");
  1045.  
  1046.     for(pl = permlinks; pl; pl = pl->next)
  1047.     if(pl->fd == s) {
  1048.         permlink = 1;
  1049.         pl->convection = cp;
  1050.         if(pl->command != NULLCHAR)
  1051.         usprintf(s,"%s",pl->command);
  1052.         cp->xmitted += usprintf(s,"/\377\200HOST %s\n",Hostname);
  1053.     }
  1054.  
  1055.     if(!permlink) {
  1056. #ifdef MAILBOX
  1057.     getpeername(s,fsocket,&len);
  1058.     ccp = strdup(psocket(fsocket));
  1059.     if((cccp = strchr(ccp,':')) != NULLCHAR)
  1060.         *cccp = '\0';
  1061.     if(strcmp(ccp,inet_ntoa(Ip_addr)) != 0)
  1062. #endif
  1063.         usprintf(cp->fd,"pse login with '/n <call>'\n");
  1064. #ifdef MAILBOX
  1065.     free(ccp);    /* have to be free()d */
  1066. #endif
  1067.     }
  1068.  
  1069.     for(;;) {
  1070. loop:
  1071.     if(cp->type == CT_CLOSED)
  1072.         break;
  1073.     if((size = recvline(cp->fd,cp->ibuf,CBUFLEN)) <= 0)
  1074.         break;
  1075.     cp->received += size;
  1076.     clear_locks();
  1077.     cp->locked = 1;
  1078.     if((ccp = strpbrk(cp->ibuf,"\r\n")) != NULLCHAR)
  1079.         *ccp = '\0';
  1080.     if(*cp->ibuf == '/') {
  1081.         arglen = strlen(arg = getarg(cp->ibuf + 1,0));
  1082.         for(cmdp = cmdtable; cmdp->name; cmdp++)
  1083.         if(!strnicmp(cmdp->name,arg,arglen)) {
  1084.             if(cmdp->states & (1 << cp->type))
  1085.             (*cmdp->fnc)(cp);
  1086.             goto loop;
  1087.         }
  1088.         if(cp->type == CT_USER)
  1089.         cp->xmitted += usprintf(cp->fd,
  1090.             "*** Unknown command '/%s'. Type /? for help.\n",arg);
  1091.         goto loop;
  1092.     }
  1093.     if(isprint(*cp->ibuf) != 0 && cp->type == CT_USER)
  1094.         send_msg_to_channel(cp->name,cp->channel,cp->ibuf);
  1095.     }
  1096.     bye_command(cp);
  1097.     free_closed_connections();
  1098.     return;
  1099. }
  1100.  
  1101.  
  1102. #endif /* CHATNODE */
  1103.